package com.gxc.string;

/**
 * 给定一个字符串，如果该字符串符合人们日常书写一个整数的形式，返回int类型的这个数;
 * 如果不符合或者越界返回-1或者报错。
 *
 * 边界
 * -2147483648
 * 2147483647
 *
 * 解法：
 * 1.不允许出现除了数字和 - 以外的字符，出现则返回-1
 * 2.如果出现 '-' ，'-' 必须在第一位，且后面 '-' 后必须跟着数字，且不能为0
 * 3.如果第一位是0，则后面 '0' 不跟着数字
 * 4.越界问题
 * 5.从高位*10 判断是否越界。
 * 用负数来记录当前已经计算到的数字（负数比正数大一位。用正数算不了 2147483648，用负数可以判断正数）
 *
 * 知识点：
 * 1.负数可以承载的绝对值比正数的绝对值大
 */
public class Integer {

    public static void main(String[] args) {
        System.out.println(strToInteger("2147483647"));
        System.out.println("---------");
        System.out.println( -2147483648/10);
        System.out.println(-2147483648%10);
        System.out.println(isValid("0".toCharArray()));
        System.out.println(isValid("01".toCharArray()));

        System.out.println(isValid2("0".toCharArray()));
        System.out.println(isValid2("01".toCharArray()));

        System.out.println(isValid3("0".toCharArray()));
        System.out.println(isValid3("01".toCharArray()));
    }

    public static int strToInteger(String str) {
        if (str == null || str.length()==0) return -1;

        char[] chars = str.toCharArray();
        if (!isValid(chars)) {
            return -1;
        }

        int multiMax = java.lang.Integer.MIN_VALUE/10;//    -2147483648/10
        int remain = java.lang.Integer.MIN_VALUE%10;//    -2147483648%10
        //判断是否是负数
        boolean neg = chars[0] == '-'?true:false;
        //当前数
        int res = 0;
        //负数从1开始，正数从0开始
        for (int i = neg?1:0; i < chars.length; i++) {
            //不管现在转化的是正数还是负数，统一用负数转，因为INT_MIN的绝对值范围比INT_MAX的范围大1，如果要转换的数是INT_MIN，用正数转会溢出
            int cur = '0' - chars[i];
            if (res<multiMax || (res == multiMax && cur<remain)) {
                //负数越界问题
                return -1;
            }
            res = res*10+cur;
        }
        //如果非负数，又达到了2147483648，则越界，负数可以达到 -2147483648
        if (!neg && res == java.lang.Integer.MIN_VALUE) return -1;
        return neg?res:-res;
    }

    /**
     * 字符是否合法
     * @param chars
     * @return
     */
    public static boolean isValid(char[] chars){
        //不允许出现除了数字和 - 以外的字符
        //如果出现 '-' ，'-' 必须在第一位
        for (int i = 0; i < chars.length; i++) {
            if (chars[i]!= '-' && chars[i] <'0' && chars[i]>'9') return false;
            else if (chars[i] == '-' && i>0) return false;
        }
        //'-' 在第一位，且后面 '-' 后必须跟着数字，且不能为0
        if (chars[0] == '-' && (chars.length<2 || chars[1]=='0')) return false;
        //如果第一位是0，则后面 '0' 不跟着数字
        if (chars[0] == '0' && chars.length>1) return false;
        return true;
    }

    /**
     * 字符是否合法
     * @param chars
     * @return
     */
    public static boolean isValid2(char[] chars){
        //0位允许 - 数字 字符
        if (chars[0] == '-' && chars[0]<'0' && chars[0]>'9') return false;
        //'-' 在第一位，且后面 '-' 后必须跟着数字，且不能为0
        if (chars[0] == '-' && (chars.length<2 || chars[1]=='0')) return false;
        //如果第一位是0，则后面 '0' 不跟着数字
        if (chars[0] == '0' && chars.length>1) return false;
        //从1位开始不允许出现除了数字的字符
        for (int i = 1; i < chars.length; i++) {
            if (chars[i] <'0' && chars[i]>'9') return false;
        }
        return true;
    }

    /**
     * 网上--有错误，没判断   如果第一位是0，则后面 '0' 不跟着数字
     * @param chars
     * @return
     */
    public static boolean isValid3(char[] chars){
        //0位允许 - 数字 字符
        if (chars[0] == '-' && chars[0]<'0' && chars[0]>'9') return false;
        //'-' 在第一位，且后面 '-' 后必须跟着数字，且不能为0
        if (chars[0] == '-' && (chars.length==1 || chars[1]=='0')) return false;
        //从1位开始不允许出现除了数字的字符
        for (int i = 1; i < chars.length; i++) {
            if (chars[i] <'0' && chars[i]>'9') return false;
        }
        return true;
    }
}
